import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { DiscordSnowflake } from "@sapphire/snowflake";
import { plainToInstance } from "class-transformer";
import { In, Repository } from "typeorm";
import { ResultMsg } from "@/common/enum/result-msg.enum";
import Result from "@/common/utils/result.util";
import { SysDictItem } from "@/database/entity/SysDictItem";
import { CreateDictItemDto } from "./dto/create-dict-item.dto";
import { UpdateDictItemDto } from "./dto/update-dict-item.dto";
import { DictItemDetailVo } from "./vo/dict-item-detail.vo";
import { DictItemListVo } from "./vo/dict-item-list.vo";
import { DictItemOptionVo } from "./vo/dict-item-option.vo";

@Injectable()
export class DictItemService {
    constructor(@InjectRepository(SysDictItem) private readonly dictItemRepository: Repository<SysDictItem>) {}

    /** 新增字典项 */
    async create(data: CreateDictItemDto) {
        const id = DiscordSnowflake.generate().toString();
        const newData = this.dictItemRepository.create({ ...data, id });
        const res = await this.dictItemRepository.save(newData);
        if (res.id) {
            return Result.success(id, ResultMsg.CREATE_SUCCESS);
        } else {
            return Result.error(ResultMsg.CREATE_ERROR);
        }
    }

    /** 删除字典项 */
    async remove(id: string) {
        await this.dictItemRepository.update(id, { deletedAt: new Date() });
        return Result.success(null, ResultMsg.DELETE_SUCCESS);
    }

    /** 更新字典项 */
    async update(data: UpdateDictItemDto) {
        const res = await this.dictItemRepository.update(data.id, { ...data });
        if (res.affected && res.affected > 0) {
            return Result.success(null, ResultMsg.UPDATE_SUCCESS);
        } else {
            return Result.error(ResultMsg.UPDATE_ERROR);
        }
    }

    /** 设为默认值 */
    async updateDefault(id: string, typeCode: string) {
        await this.dictItemRepository.update({ typeCode }, { default: false });
        await this.dictItemRepository.update(id, { default: true });
        return Result.success(null, ResultMsg.HANDLE_SUCCESS);
    }

    /** 取消默认 */
    async cancelDefault(id: string) {
        await this.dictItemRepository.update(id, { default: false });
        return Result.success(null, ResultMsg.HANDLE_SUCCESS);
    }

    /** 查询单个记录 */
    async findById(id: string): Promise<Result<DictItemDetailVo>> {
        const record = await this.dictItemRepository.findOne({
            select: ["id", "name", "value", "status", "rank", "remark", "default"],
            where: { id },
        });
        const detailVo = plainToInstance(DictItemDetailVo, record, { excludeExtraneousValues: true });
        return Result.success(detailVo);
    }

    /** 获取下拉选项 */
    async listOptions(typeCodes: string[]): Promise<Result<Record<string, DictItemOptionVo[]>>> {
        const list = await this.dictItemRepository.find({
            select: ["id", "name", "value", "default", "typeCode"],
            where: { typeCode: In(typeCodes), status: true },
            order: {
                rank: "ASC",
                name: "ASC",
            },
        });

        const map = new Map<string, DictItemOptionVo[]>();

        list.forEach((item) => {
            if (!map.has(item.typeCode)) {
                map.set(item.typeCode, []);
            }
            map.get(item.typeCode)?.push(item as any);
        });

        const ans: Record<string, DictItemOptionVo[]> = {};

        for (const [key, value] of map.entries()) {
            const voList = plainToInstance(DictItemOptionVo, value, { excludeExtraneousValues: true });
            ans[key] = voList;
        }

        return Result.success(ans);
    }

    /** 获取列表 */
    async list(typeCode: string): Promise<Result<DictItemListVo[]>> {
        const list = await this.dictItemRepository.find({
            select: ["id", "name", "value", "status", "rank", "default"],
            where: {
                typeCode,
            },
            order: {
                rank: "ASC",
                name: "ASC",
            },
        });
        const voList = plainToInstance(DictItemListVo, list, { excludeExtraneousValues: true });
        return Result.success(voList);
    }
}
